-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: restart dev-server on config change #21212
Conversation
Thanks for taking the time to open a PR!
|
Test summaryRun details
View run in Cypress Dashboard ➡️ Failures
Flakiness
This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard |
} | ||
|
||
if (this._currentTestingType === 'component') { | ||
const devServerOptions = await this.ctx._apis.projectApi.getDevServer().start({ specs: this.ctx.project.specs, config: finalConfig }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an unhandled edge-case here. If the user modifies their webpack config such that the port of the dev-server is changed, serving tests will fail. We would need to shut down and restart the server in order to fix this, but this seems like a fairly large refactor and not just ct specific.
I haven't done an audit of all config options, but there are a few options that would require a server restart such as watchForFileChanges
or hosts
which we currently aren't handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be CT specific since E2E does not use the dev-server.
Also isn't the port always randomly assigned each time webpack-dev-server starts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far my testing has shown that the dev-servers will default to the same port used, I only saw a port switch when explicitly changing the port in the webpackConfig
. What I have wired up isn't fullproof, but we have UNIFY-1696 to properly handle config changes that require a server restart.
cy.openProject('cypress-in-cypress') | ||
cy.startAppServer('component') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we needed to move this from the beforeEach
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was another test that were duplicating the openProject
and startAppServer
call with different arguments, I'm not a fan of calling these more than once so I decided to move them out and into each test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's fine, I wonder if that's an indication we should have a second describe
block then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 8cabb60
const { ctDevServerPort } = await this.initializeSpecsAndDevServer(cfg) | ||
|
||
if (this.testingType === 'component') { | ||
cfg.baseUrl = `http://localhost:${ctDevServerPort}` | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad we're getting rid of this from here
if (this._currentTestingType === 'component') { | ||
// Since we refresh the dev-server on config changes, we need to close it and clean up it's listeners | ||
// before we can start a new one. This needs to happen before we have registered the events of the child process | ||
this.ctx._apis.projectApi.getDevServer().close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the implementation of getDevServer().close()
it looks like it sends close
, but I don't see anywhere that it's listened to on the child end 🤔 .
There's also this block:
baseEmitter.on('dev-server:close', () => {
debug('base emitter plugin close event')
ipc.send('dev-server:close')
})
but I don't see anywhere that's in-use, either on the issuing end or the receiving end?
Was mostly looking for this close
contract to see if we should be await'ing it being closed, rather than firing & trying to re-init, but if I'm reading the code correctly, it doesn't even seem like it's being used - I think we're just relying on it getting auto-closed when the child process is killed.
So my question is - do we want to clean this up so we're closing the server properly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm honestly not too familiar with the IPC communication, I was just trying to lift and keep the same contract that existed before. There is a close function returned with the dev-servers, maybe this is the missing link. Like you said, seems like we are just relying on the child process being auto-killed, I can confirm that the new server spawned doesn't conflict with the old as there would be a port in use error thrown but maybe there is a potential race condition here. I'll dig in a bit, could use some help in this area though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dug into this a bit and landed on just removing the unused close functions and event. Killing the child process is safe in terms of cleanup, and we weren't calling the close
functions from the dev-servers to begin with. I think we could put in a system to allow these child processes to have a cleanup step, but that's outside of the scope of this issue. I can followup with an issue if this is something we should pursue.
sinon.stub(ctx._apis.projectApi.getDevServer(), 'close') | ||
const devServerReady = | ||
new Promise((res) => { | ||
ctx._apis.projectApi.getDevServer().emitter.on('dev-server:compile:success', (err) => res(true)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we doing anything with the value that's resolved? Should this be:
ctx._apis.projectApi.getDevServer().emitter.on('dev-server:compile:success', (err) => res(true)) | |
ctx._apis.projectApi.getDevServer().emitter.on('dev-server:compile:success', (err) => res()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 8cabb60
@@ -2,10 +2,10 @@ describe('Spec List - Git Status', () => { | |||
beforeEach(() => { | |||
cy.scaffoldProject('cypress-in-cypress') | |||
.then((projectPath) => { | |||
cy.task('initGitRepoForTestProject', projectPath) | |||
cy.wait(500) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're moving stuff around, is this wait still needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope! 4bd8b90
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely fixes a lot of bugs, but looks like we need a bit of work around the hot reload - seems HMR dies after the restart.
I commented in the issue and added a video reproduction: https://cypress-io.atlassian.net/browse/UNIFY-1236?focusedCommentId=17992
} | ||
|
||
if (this._currentTestingType === 'component') { | ||
const devServerOptions = await this.ctx._apis.projectApi.getDevServer().start({ specs: this.ctx.project.specs, config: finalConfig }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be CT specific since E2E does not use the dev-server.
Also isn't the port always randomly assigned each time webpack-dev-server starts?
@@ -308,46 +300,6 @@ export class ProjectBase<TServer extends Server> extends EE { | |||
options.onError(err) | |||
} | |||
|
|||
async initializeSpecsAndDevServer (updatedConfig: Cfg): Promise<{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I love deleting code from project-base - I think we should be mostly getting rid of this entire thing, eventually.
@lmiller1990 I'll create a followup issue for vite not working. Since webpack is our primary audience, I'm ok with getting this merged. I believe UNIFY-1696 will fix the vite issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Known bug with the Vite restart, issue is logged.
User facing changelog
Restart dev-server when config is refreshed
Additional details
The component dev-server is killed whenever the Cypress config changes. A new child process is created, but the dev-server requires an explicit
start
for it to actually start since it is a function that is registered on thedev-server:start
event. This was only being called once during project initialization so any subsequent changes to the config would never restart the server.This PR moves the
devServer.start
event into the config loading process such that whenever the config is refreshed, the dev-server will be recreated.How has the user experience changed?
Screen.Recording.2022-04-26.at.10.23.53.AM.mov
PR Tasks
cypress-documentation
?type definitions
?cypress.schema.json
?